/*
 * acpi/tables.hh - Data types for ACPI tables.
 * Copyright (C) 2007  Mikhail Vorozhtsov
 * See the LICENSE section of the README file for details.
 */

/* $Id$ */

#ifndef HEADER_ACPI_TABLES_HH
#define HEADER_ACPI_TABLES_HH

START_NAMESPACE (acpi)

#define __ACPI_SIG32(b1,b2,b3,b4) \
  (((u32_t) (b4) << 24) | ((u32_t) (b3) << 16) \
   | ((u32_t) (b2) << 8) | (u32_t) (b1))
#define __ACPI_SIG64(b1,b2,b3,b4,b5,b6,b7,b8) \
  (((u64_t) __ACPI_SIG32 (b5, b6, b7, b8) << 32) \
   | ((u64_t) __ACPI_SIG32 (b1, b2, b3, b4)))

struct gas_t
{
  enum space_t
  {
    SYS_MEMORY = 0,
    SYS_IO = 1,
    PCI_CFG = 2,
    EMBED_CTRLR = 3,
    SMBUS = 4
  };

  u8_t space;
  u8_t reg_width;
  u8_t reg_offset; 
  u8_t access_size;
  u64_t addr;
} PACKED;

struct rsdp_t
{
  static const u64_t SIG
    = __ACPI_SIG64 ('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ');

  u64_t sig;
  u8_t chksum;
  u8_t oem_id[6];
  u8_t rev;
  u32_t rsdt_addr;
  u32_t len;
  u64_t xsdt_addr;
  u8_t ext_chksum;
  u8_t reserved[3];

  INLINE
  bool
  valid_p () const
  {
    const u8_t *str = (const u8_t *) this;
    u8_t sum = 0, ext_sum = 0;
    u32_t i;

    for (i = 0; i < offsetof (rsdp_t, len); ++i)
      {
        sum += str[i];
        ext_sum += str[i];
      }

    if (rev >= 1)
      for (; i < len - offsetof (rsdp_t, len); ++i)
        ext_sum += str[i];

    return !(sum || ext_sum);
  }
} PACKED;

struct sdt_t
{
  u32_t sig;
  u32_t len;
  u8_t rev;
  u8_t chksum;
  u8_t oem_id[6];
  u64_t oem_tbl_id;
  u32_t oem_rev;
  u32_t creator_id;
  u32_t creator_rev;

  INLINE
  bool
  valid_p () const
  {
    const u8_t *str = (const u8_t *) this;
    u8_t sum = 0;

    for (u32_t i = 0; i < len; ++i)
      sum += str[i];

    return sum == 0;
  }
} PACKED;

struct rsdt_t : public sdt_t
{
  static const u32_t SIG = __ACPI_SIG32 ('R', 'S', 'D', 'T');

  u32_t entries[];
} PACKED;

struct xsdt_t : public sdt_t
{
  static const u32_t SIG = __ACPI_SIG32 ('X', 'S', 'D', 'T');

  u64_t entries[];
} PACKED;

struct fadt_t : public sdt_t
{
  union flag_t
  {
    struct
      {
        u32_t WBINVD : 1;
        u32_t WBINVD_FLUSH : 1;
        u32_t PROC_C1 : 1;
        u32_t P_LVL2_UP : 1;
        u32_t PWR_BTN : 1;
        u32_t SLP_BTN : 1;
        u32_t FIX_RTC : 1;
        u32_t RTC_S4 : 1;
        u32_t TMR_VAL_EXT : 1;
        u32_t DCK_CAP : 1;
        u32_t RESET_REG_SUP : 1;
        u32_t SEALED_CASE : 1;
        u32_t HEADLESS : 1;
        u32_t CPU_SW_SLP : 1;
        u32_t PCI_EXP_WAK : 1;
        u32_t USE_PLATFORM_CLOCK : 1;
        u32_t S4_RTC_STS_VALID : 1;
        u32_t REMOTE_POWER_ON_CAPABLE : 1;
        u32_t FORCE_APIC_CLUSTER_MODEL : 1;
        u32_t FORCE_APIC_PHYS_DST_MODE : 1;
        u32_t : 12;
      };
    u32_t raw;
  };

  union iapc_boot_flag_t
  {
    struct
      {
        u16_t LEGACY_DEVS : 1;
        u16_t CTLR_8042 : 1;
        u16_t NO_VGA : 1;
        u16_t NO_MSI : 1;
        u16_t : 12;
      };
    u16_t raw;
  };

  static const u32_t SIG = __ACPI_SIG32 ('F', 'A', 'C', 'P');

  u32_t facs_addr;
  u32_t dsdt_addr;
  u8_t : 8;
  u8_t pref_pm_profile;
  u16_t sci_int;
  u32_t sci_cmd;
  u8_t acpi_enable;
  u8_t acpi_disable;
  u8_t s4bios_req;
  u8_t pstate_cnt;
  u32_t pm1a_evt_blk;
  u32_t pm1b_evt_blk;
  u32_t pm1a_cnt_blk;
  u32_t pm1b_nct_blk;
  u32_t pm2_cnt_blk;
  u32_t pm_tmr_blk;
  u32_t gpe0_blk;
  u32_t gpe1_blk;
  u8_t pm1_evt_len;
  u8_t pm1_cnt_len;
  u8_t pm2_cnt_len;
  u8_t pm_tmr_len;
  u8_t gpe0_blk_len;
  u8_t gpe1_blk_len;
  u8_t gpe1_base;
  u8_t cst_cnt;
  u16_t p_lvl2_lat;
  u16_t p_lvl3_lat;
  u16_t flush_size;
  u16_t flush_stride;
  u8_t duty_offset;
  u8_t duty_width;
  u8_t day_alrm;
  u8_t mon_alrm;
  u8_t century;
  iapc_boot_flag_t iapc_boot_flags;
  u8_t : 8;
  flag_t flags;
  gas_t reset_reg;
  u8_t reset_val;
  u8_t reserved[3];
  u64_t x_facs_addr;
  u64_t x_dsdt_addr;
  gas_t x_pm1a_evt_blk;
  gas_t x_pm1b_evt_blk;
  gas_t x_pm1a_cnt_blk;
  gas_t x_pm1b_cnt_blk;
  gas_t x_pm2_cnt_blk;
  gas_t x_pm_tmr_blk;
  gas_t x_gpe0_blk;
  gas_t x_gpe1_blk;
} PACKED;

struct madt_t : public sdt_t
{
  struct entry_t
  {
    enum type_t
    {
      TYPE_LAPIC = 0,
      TYPE_IOAPIC = 1,
      TYPE_INT_SRC_OVERRIDE = 2,
      TYPE_NMI_SRC = 3,
      TYPE_LAPIC_NMI = 4,
      TYPE_LAPIC_OVERRIDE = 5,
      TYPE_IOSAPIC = 6,
      TYPE_LSAPIC = 7,
      TYPE_PLATFORM_INT_SRC = 8
    };

    u8_t type;
    u8_t len;
  } PACKED;

  struct ioapic_t : public entry_t
  {
    u8_t id;
    u8_t reserved;
    u32_t addr;
    u32_t ints_base;
  } PACKED;

  struct lapic_override_t : public entry_t
  {
    u16_t reserved;
    u64_t addr;
  } PACKED;

  static const u32_t SIG = __ACPI_SIG32 ('A', 'P', 'I', 'C');

  u32_t lapic_base;
  u32_t apic_flags;
} PACKED;

#undef __ACPI_SIG64
#undef __ACPI_SIG32

END_NAMESPACE

#endif /* HEADER_ACPI_TABLES_HH */

